/*
 * N-Step-SCAN.c
 *
 *  Created on: 13/11/2011
 *      Author: utn_so
 */

#include "libPPD.h"
#include "N-Step-SCAN.h"

void sincronizarListas ()
{
	extern t_config config;
	extern sem_t listaPedidosVacia;
	extern sem_t sublistaLlena;

	while (1)
	{
		sem_wait (&listaPedidosVacia);
		sem_wait (&sublistaLlena);

		if ((strcmp(config.modoInicio, "CONNECT") == 0))
			sublistaLlenaAListaPedidosPRAID ();
		else if (strcmp(config.modoInicio, "LISTEN") == 0)
			sublistaLlenaAListaPedidosPFS ();

	}
}

void sublistaLlenaAListaPedidosPRAID ()
{
	extern tNListaPRAID *listaPRAID;
	extern t_listaPRAID *listaPedidosPRAID;
	extern pthread_mutex_t bloqueaNLista;
	extern sem_t semaforoLista;
	int32_t bloquearLista;
	int32_t i=0;

	tNodoNListaRAID *nodoAux;
	tNodoNListaRAID *nodo;
	bloquearLista = pthread_mutex_lock(&bloqueaNLista);
	nodoAux = listaPRAID->head;

	while (nodoAux->sublistaN->head == NULL && nodoAux->next != NULL)
	{
		nodoAux = nodoAux->next;
	}

	if(nodoAux != NULL && nodoAux->sublistaN->head != NULL)
	{
		listaPedidosPRAID = nodoAux->sublistaN;
		nodo = listaPRAID->head;
		listaPRAID->head = nodoAux;
		while (i < listaPRAID->head->cantPedidos)
		{
			sem_post(&semaforoLista);
			i++;
		}
		free(nodo);
		nodo = NULL;
	}
	else
	{
		free(nodoAux);
		listaPRAID->head = NULL;
	}
	bloquearLista = pthread_mutex_unlock(&bloqueaNLista);

}


int32_t planificarN_Step_SCAN_RAID (t_NIPC paquete)
{
	extern tCabezal cabezalAux;
	extern t_config config;
	extern tNListaPRAID *listaPRAID;
	extern t_listaPRAID *listaPedidosPRAID;
	extern sem_t semaforoLista;
	extern sem_t sublistaLlena;
	extern pthread_mutex_t bloqueaNLista;
	extern int32_t primerNodoLista;
	int32_t bloquearLista;
	t_CHS sectorCHS;
	int32_t posicion = 0;

	loguearTipoPedido (paquete);
	bloquearLista = pthread_mutex_lock(&bloqueaNLista);

	if (listaPRAID->head == NULL)
	{
		primerNodoLista = 0;
		agregarNodoNListaPRAID (posicion, paquete);
		listaPedidosPRAID = listaPRAID->head->sublistaN;
		sem_post (&semaforoLista);
	}
	else
	{
		tNodoNListaRAID *nodoAux;
		nodoAux = listaPRAID->head;

		while (nodoAux->cantPedidos == config.cantPedidos && nodoAux->next != NULL)
		{
			nodoAux = nodoAux->next;
			posicion++;
		}

		posicion++;

		if (nodoAux->cantPedidos != config.cantPedidos)
		{
			agregarPedidosPRAID (nodoAux->sublistaN, paquete);
			nodoAux->cantPedidos++;

			if (nodoAux->cantPedidos == config.cantPedidos)
			{
				t_nodoPRAID *nodoSublista;
				nodoSublista = nodoAux->sublistaN->head;

				while (nodoSublista->next != NULL)
				{
					nodoSublista = nodoSublista->next;
				}

				pasarACHS (nodoSublista->paquete.nroSector, &sectorCHS);

				if (cabezalAux.sentido == ASCENDENTE)
				{
					if (cabezalAux.posActual.C < sectorCHS.C)
						cabezalAux.sentido = ASCENDENTE;
					else
						cabezalAux.sentido = DESCENDENTE;
				}
				else if (cabezalAux.sentido == DESCENDENTE)
				{
					if (cabezalAux.posActual.C < sectorCHS.C)
						cabezalAux.sentido = ASCENDENTE;
					else
						cabezalAux.sentido = DESCENDENTE;
				}
				cabezalAux.posActual.C = sectorCHS.C;
				cabezalAux.posActual.S = sectorCHS.S+1;

				sem_post(&sublistaLlena);
			}

			if(listaPedidosPRAID == nodoAux->sublistaN)
				sem_post(&semaforoLista);
		}

		else if (nodoAux->next == NULL)
			agregarNodoNListaPRAID (posicion, paquete);
	}
	bloquearLista = pthread_mutex_unlock(&bloqueaNLista);
	return Retorno_OK;
}

void agregarNodoNListaPRAID (int32_t posicion, t_NIPC paquete)
{
	extern t_listaPRAID *listaPedidosPRAID;
	extern tNListaPRAID *listaPRAID;
	extern sem_t semaforoLista;
	extern int32_t primerNodoLista;
	int32_t cont = 0;

	tNodoNListaRAID *nvoNodo = (tNodoNListaRAID *) malloc (sizeof (tNodoNListaRAID));

	nvoNodo->cantPedidos = 0;
	nvoNodo->sublistaN = crearListaPRAID();
	nvoNodo->next = NULL;

	tNodoNListaRAID *nodoAux = NULL;
	nodoAux = listaPRAID->head;

	if( posicion == 0)
	{
		nvoNodo->next = listaPRAID->head;
		listaPRAID->head = nvoNodo;
	}

	else if (posicion > 0)
	{
		nodoAux = listaPRAID->head;
		for(cont=0 ; cont < (posicion-1); nodoAux = nodoAux->next,cont++);
		nvoNodo->next = nodoAux->next;
		nodoAux->next = nvoNodo;
	}

	agregarPedidosPRAID (nvoNodo->sublistaN, paquete);
	if(primerNodoLista == 0)
		primerNodoLista = 1;
	else if(listaPedidosPRAID == nvoNodo->sublistaN)
		sem_post(&semaforoLista);

	nvoNodo->cantPedidos++;
}

void crearNListaPRAID () // va en el main!!!!!
{
	extern tNListaPRAID *listaPRAID;
	listaPRAID = (tNListaPRAID *) malloc (sizeof(tNListaPRAID));
	listaPRAID->head = NULL;
}

void agregarPedidosPRAID (t_listaPRAID *sublista, t_NIPC paquete)
{
	extern tCabezal cabezalAux;
	t_CHS sectorCHS;

	pasarACHS (paquete.nroSector, &sectorCHS);

	if (cabezalAux.sentido == ASCENDENTE) // Tiene que ordenar los mayores al cabezal creciente y los que son menor al cabezal en orden decreciente despues de los que son mayor.
	{
		if (cabezalAux.posActual.C <= sectorCHS.C)
			despuesDelCabezalAscendentePRAID (sublista, paquete); //menor a mayor

		else if (cabezalAux.posActual.C > sectorCHS.C)
			antesDelCabezalAscendentePRAID (sublista, paquete);
	}
	if (cabezalAux.sentido == DESCENDENTE) // Tiene que ordenar los menores al cabezal en forma decreciente y los que son mayor al cabezal ponerlos al final de los menores ordenados en forma creciente.
	{
		if (cabezalAux.posActual.C >= sectorCHS.C)
			despuesDelCabezalDescendentePRAID (sublista, paquete); //menor a mayor

		else if (cabezalAux.posActual.C < sectorCHS.C)
			antesDelCabezalDescendentePRAID (sublista, paquete); //mayor a menor
	}
}

void agregarListaPRAID(int32_t posicion, t_listaPRAID *sublista, t_NIPC paqueteNuevo)
{
	extern t_log *loguear;
	int32_t cont = 0;
	t_nodoPRAID* nodo = NULL;

	t_nodoPRAID *nuevoNodo;
	nuevoNodo = (t_nodoPRAID *) calloc (1, sizeof(t_nodoPRAID));
	NIPC_crearpaquete(paqueteNuevo.DescriptorID, paqueteNuevo.PayloadDescriptor, paqueteNuevo.PayloadLength, paqueteNuevo.payload, paqueteNuevo.nroSector, &nuevoNodo->paquete);

	if( posicion == 0)
	{
		nuevoNodo->next = sublista->head;
		sublista->head = nuevoNodo;
	}
	else if (posicion > 0)
	{
		nodo = sublista->head;
		for( cont=0 ; cont < (posicion-1); nodo=nodo->next,cont++ );
		nuevoNodo->next =  nodo->next;
		nodo->next = nuevoNodo;
	}
	else
	{
		log_error (loguear, "PPD", "Message error: %s", "Posición negativa, no se puede agregar a la lista");
	}

}

void despuesDelCabezalAscendentePRAID (t_listaPRAID *sublista, t_NIPC paqueteNuevo)
{
	extern tCabezal cabezalAux;

	if (sublista->head == NULL)
		agregarListaPRAID(0, sublista, paqueteNuevo);

	else
	{
		int32_t posicion = 0;
		int32_t salir = 0;
		int32_t pistaNodo, pistaNuevo;
		t_CHS sectorCHSNodo;
		t_CHS sectorCHSNuevo;

		t_nodoPRAID *nodo;
		nodo = sublista->head;

		pasarACHS (nodo->paquete.nroSector, &sectorCHSNodo);
		pistaNodo = sectorCHSNodo.C;

		pasarACHS (paqueteNuevo.nroSector, &sectorCHSNuevo);
		pistaNuevo = sectorCHSNuevo.C;

		/* mientras que la pista del que esta en la lista sea mayor o igual al cabezal, porque si es menor deberia atenderlo a la vuelta,
		   sea menor al nuevo que quiero insertar para que quede ordenado ascendente,
		   y salir distinto de uno para que se sepa si es el ultimo nodo de la lista y no se puede avanzar m�s */
		//bloquearCabezal = pthread_mutex_lock(&cabezal.bloqueaCabezal);

		while ((pistaNodo >= cabezalAux.posActual.C) && (pistaNodo < pistaNuevo ) && (salir != 1))
		{
			posicion++;
			if (nodo->next == NULL)
				salir = 1;
			else
			{
				nodo = nodo->next;
				pistaNodo = numeroPista(nodo->paquete.nroSector);
			}
		}

		salir = 0;
		while ((pistaNodo == pistaNuevo) && (salir != 1))
		{
			if (nodo->paquete.nroSector == paqueteNuevo.nroSector)
			{
				while ((nodo->paquete.nroSector == paqueteNuevo.nroSector) && (salir == 0))
				{
					//Sectores iguales, si el que ya esta es de Escritura, el nuevo lo pongo una posici�n m�s.
					if (nodo->paquete.PayloadDescriptor == ESCRIBIRSECTOR)
					{
						posicion++;
						if (nodo->next == NULL)
							salir = 1;
						else
						{
							nodo = nodo->next;
							pistaNodo = numeroPista(nodo->paquete.nroSector);
						}
					}
					else
						salir = 1;
				}
			}
			else //las pistas son iguales pero no son el mismo sector, hago fifo, primero la que ya estaba.
			{
				posicion++;
				if (nodo->next == NULL)
					salir = 1;
				else
				{
					nodo = nodo->next;
					pistaNodo = numeroPista(nodo->paquete.nroSector);
				}

			}
		}

		agregarListaPRAID(posicion, sublista, paqueteNuevo);
	}
}

void antesDelCabezalAscendentePRAID (t_listaPRAID *sublista, t_NIPC paqueteNuevo)
{
	extern tCabezal cabezalAux;

	if (sublista->head == NULL)
		agregarListaPRAID(0, sublista, paqueteNuevo);

	else
	{
		int32_t posicion = 0;
		int32_t salir = 0;
		int32_t pistaNodo, pistaNuevo;
		t_CHS sectorCHSNodo;
		t_CHS sectorCHSNuevo;

		t_nodoPRAID *nodo;
		nodo = sublista->head;

		pasarACHS (nodo->paquete.nroSector, &sectorCHSNodo);
		pistaNodo = sectorCHSNodo.C;

		pasarACHS (paqueteNuevo.nroSector, &sectorCHSNuevo);
		pistaNuevo = sectorCHSNuevo.C;

		while (((pistaNodo >= cabezalAux.posActual.C) || (pistaNodo > pistaNuevo )) && (salir != 1))
		{
			posicion++;
			if (nodo->next == NULL)
				salir = 1;
			else
			{
				nodo = nodo->next;
				pistaNodo = numeroPista(nodo->paquete.nroSector);
			}
		}

		salir = 0;
		while ((pistaNodo == pistaNuevo) && (salir != 1))
		{
			if (nodo->paquete.nroSector == paqueteNuevo.nroSector)
			{
				while ((nodo->paquete.nroSector == paqueteNuevo.nroSector) && (salir == 0))
				{
					//Sectores iguales, si el que ya esta es de Escritura, el nuevo lo pongo una posici�n m�s.
					if (nodo->paquete.PayloadDescriptor == ESCRIBIRSECTOR)
					{
						posicion++;
						if (nodo->next == NULL)
							salir = 1;
						else
						{
							nodo = nodo->next;
							pistaNodo = numeroPista(nodo->paquete.nroSector);
						}
					}
					else
						salir = 1;
				}
			}
			else //las pistas son iguales pero no son el mismo sector, hago fifo, primero la que ya estaba.
			{
				posicion++;
				if (nodo->next == NULL)
					salir = 1;
				else
				{
					nodo = nodo->next;
					pistaNodo = numeroPista(nodo->paquete.nroSector);
				}
			}
		}

		agregarListaPRAID(posicion, sublista, paqueteNuevo);
	}
}

void despuesDelCabezalDescendentePRAID (t_listaPRAID *sublista, t_NIPC paqueteNuevo)
{
	extern tCabezal cabezalAux;

	if (sublista->head == NULL)
		agregarListaPRAID(0, sublista, paqueteNuevo);

	else
	{
		int32_t posicion = 0;
		int32_t salir = 0;
		int32_t pistaNodo, pistaNuevo;
		t_CHS sectorCHSNodo;
		t_CHS sectorCHSNuevo;

		t_nodoPRAID *nodo;
		nodo = sublista->head;

		pasarACHS (nodo->paquete.nroSector, &sectorCHSNodo);
		pistaNodo = sectorCHSNodo.C;

		pasarACHS (paqueteNuevo.nroSector, &sectorCHSNuevo);
		pistaNuevo = sectorCHSNuevo.C;

		while ((pistaNodo <= cabezalAux.posActual.C) && (pistaNodo > pistaNuevo ) && (salir != 1))
		{
			posicion++;
			if (nodo->next == NULL)
				salir = 1;
			else
			{
				nodo = nodo->next;
				pistaNodo = numeroPista(nodo->paquete.nroSector);
			}
		}

		salir = 0;
		while ((pistaNodo == pistaNuevo) && (salir != 1))
		{
			if (nodo->paquete.nroSector == paqueteNuevo.nroSector)
			{
				while ((nodo->paquete.nroSector == paqueteNuevo.nroSector) && (salir == 0))
				{
					//Sectores iguales, si el que ya esta es de Escritura, el nuevo lo pongo una posici�n m�s.
					if (nodo->paquete.PayloadDescriptor == ESCRIBIRSECTOR)
					{
						posicion++;
						if (nodo->next == NULL)
							salir = 1;
						else
						{
							nodo = nodo->next;
							pistaNodo = numeroPista(nodo->paquete.nroSector);
						}
					}
					else
						salir = 1;
				}
			}
			else //las pistas son iguales pero no son el mismo sector, hago fifo, primero la que ya estaba.
			{
				posicion++;
				if (nodo->next == NULL)
					salir = 1;
				else
				{
					nodo = nodo->next;
					pistaNodo = numeroPista(nodo->paquete.nroSector);
				}
			}
		}

		agregarListaPRAID(posicion, sublista, paqueteNuevo);
	}
}

void antesDelCabezalDescendentePRAID (t_listaPRAID *sublista, t_NIPC paqueteNuevo)
{
	extern tCabezal cabezalAux;

	if (sublista->head == NULL)
		agregarListaPRAID(0, sublista, paqueteNuevo);

	else
	{
		int32_t posicion = 0;
		int32_t salir = 0;
		int32_t pistaNodo, pistaNuevo;
		t_CHS sectorCHSNodo;
		t_CHS sectorCHSNuevo;

		t_nodoPRAID *nodo;
		nodo = sublista->head;

		pasarACHS (nodo->paquete.nroSector, &sectorCHSNodo);
		pistaNodo = sectorCHSNodo.C;

		pasarACHS (paqueteNuevo.nroSector, &sectorCHSNuevo);
		pistaNuevo = sectorCHSNuevo.C;

		while (((pistaNodo <= cabezalAux.posActual.C) || (pistaNodo < pistaNuevo )) && (salir != 1))
		{
			posicion++;
			if (nodo->next == NULL)
				salir = 1;
			else
			{
				nodo = nodo->next;
				pistaNodo = numeroPista(nodo->paquete.nroSector);
			}
		}

		salir = 0;
		while ((pistaNodo == pistaNuevo) && (salir != 1))
		{
			if (nodo->paquete.nroSector == paqueteNuevo.nroSector)
			{
				while ((nodo->paquete.nroSector == paqueteNuevo.nroSector) && (salir == 0))
				{
					//Sectores iguales, si el que ya esta es de Escritura, el nuevo lo pongo una posici�n m�s.
					if (nodo->paquete.PayloadDescriptor == ESCRIBIRSECTOR)
					{
						posicion++;
						if (nodo->next == NULL)
							salir = 1;
						else
						{
							nodo = nodo->next;
							pistaNodo = numeroPista(nodo->paquete.nroSector);
						}
					}
					else
						salir = 1;
				}
			}
			else //las pistas son iguales pero no son el mismo sector, hago fifo, primero la que ya estaba.
			{
				posicion++;
				if (nodo->next == NULL)
					salir = 1;
				else
				{
					nodo = nodo->next;
					pistaNodo = numeroPista(nodo->paquete.nroSector);
				}

			}
		}
		agregarListaPRAID(posicion, sublista, paqueteNuevo);
	}
}
